package com.example.demo10_json_login.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //配置明文加密方式
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    // 配置内存用户
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("wangnian").password("123").roles("admin");
    }

    // 将 UserDetailsService 暴露出来，注入到容器中
    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

    // 将 AuthenticationManager 暴露出来，注入到容器中
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    // 放行（不走过滤器）
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/verifyCode");
    }

    // LoginFilter 注入容器
    @Bean
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(new ObjectMapper().writeValueAsString(authentication.getPrincipal()));
        });
        loginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("登录失败 " + exception.getMessage());
        });
        // 设置 AuthenticationManager
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        loginFilter.setFilterProcessesUrl("/login");
        // 给 loginFilter 设置 rememberMeServices(),因为登录成功后会调用 rememberMeServices#loginSuccess 方法生成 remember-me
        // 下次请求就会带过来，如何解析 remember-me 是否合法，解析的过滤器是 RememberMeAuthenticationFilter
        loginFilter.setRememberMeServices(rememberMeServices());
        return loginFilter;
    }

    // 自定义 rememberMeServices，传入两个参数，一个盐值，一个 UserDetailService
    @Bean
    RememberMeServices rememberMeServices() throws Exception {
        return new TokenBasedRememberMeServices("key", userDetailsServiceBean());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 把 loginFilter 放在 UsernamePasswordAuthenticationFilter 的位置
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        http.authorizeRequests()
                .anyRequest().authenticated()
                // 开启 rememberMe,rememberMeServices 使用我们自定义 rememberMeServices()
                .and().rememberMe().rememberMeServices(rememberMeServices())
                // 不开启表单登录，使用自定义 loginFilter 完成的 json 登录
//                .and()
//                .formLogin()
//                .successHandler((request, response, authentication) -> {
//                    response.setContentType("application/json;charset=UTF-8");
//                    response.getWriter().write(new ObjectMapper().writeValueAsString(authentication.getPrincipal()));
//                })
//                .failureHandler((request, response, exception) -> {
//                    response.setContentType("application/json;charset=UTF-8");
//                    response.getWriter().write("登录失败 " + exception.getMessage());
//                })
                .and()
                .exceptionHandling()
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write("认证失败 " + authException.getMessage());
                })
                .accessDeniedHandler((request, response, accessDeniedException) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write("权限校验失败 " + accessDeniedException.getMessage());
                })
                .and().csrf().disable();
    }
}
